#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "eloop.h"

static void
run_cb(eloop_t *eloop, void *data)
{
  int i = (int)data;
  printf("run_cb i=%d\n", i);
}

static int
timeout_cb(eloop_t *eloop, void *data)
{
  int *i = (int *)data;
  printf("timeout_cb i=%d\n", *i);
  *i += 1;
  if (*i % 5 == 0)
    eloop_add_run(eloop, run_cb, (void *)*i);
  return *i < 45;
}

static int
socket_io_init(int port)
{
  int s;
  struct sockaddr_in addr;

  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = 0;
  addr.sin_port = htons(port);
  
  s = socket(PF_INET, SOCK_STREAM, 0);
  if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
  {
    printf("bind error: errno=%d error=%s\n", errno, strerror(errno));
	close(s);
	return -1;
  }
  listen(s, 5);

  return s;
}

static void
socket_read(eloop_t *eloop, int s, loop_event_t le, void *data)
{
  char buf[1024];
  if (le & EVENT_IN)
  {
    int len = recv(s, buf, sizeof(buf), 0);
    if (len <= 0)
    {
      printf("recv error: %d, %s\n", errno, strerror(errno));
      eloop_remove_io_source_by_fd(eloop, s);
      close(s);
    }
    else
    {
      buf[len] = 0;
      printf("recv: %s\n", buf);
    }
  }
  if (le & EVENT_ERR)
  {
    printf("socket error: %d, %s\n", errno, strerror(errno));
    eloop_remove_io_source_by_fd(eloop, s);
    close(s);
  }
}

static void
io_handler(eloop_t *eloop, int fd, loop_event_t le, void *data)
{
  static int times = 0;
  printf("io_handler le=%x\n", le);
  if (le & EVENT_IN)
  {
    struct sockaddr_in addr;
    size_t alen = sizeof(addr);
    int s = accept(fd, (struct sockaddr *)&addr, &alen);
    printf("connect from %s:%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
    times++;
    if (times == 6)
      eloop_add_io_source(eloop, s, EVENT_IN, socket_read, NULL);
    else
      close(s);
  }
}

int main(int argc, char *argv[])
{
  eloop_t *eloop = eloop_init();
  int i = 0;
  int k = 10;

  eloop_add_io_source(eloop, socket_io_init(3456), EVENT_IN, io_handler, NULL);
  eloop_add_timeout(eloop, 1000, timeout_cb, (void*)&i);
  eloop_add_timeout(eloop, 3000, timeout_cb, (void*)&k);

  eloop_run(eloop);

  return 0;
}

